/*用于提供用户使用的接口，保证了程序的易用性*/

#ifndef INTERFACE_HPP
#define INTERFACE_HPP

#include "logger.hpp"

// 对于用户来说，如果只需要使用默认日志器，直接使用getDefaultLogger()即可，使用方法有两种：
// 1. 直接调用getDefaultLogger()获取默认日志器，然后调用日志器的接口，如_debug()等
// 2. 使用宏定义，如LOG_DEBUG()等，宏定义会自动获取默认日志器，然后调用日志器的接口

// 如果需要自定义日志器，包括定制日志器名称、限制输出等级、输出格式、落地方式等，
// 则需要使用createLogger()接口，该接口返回一个日志器对象指针，然后调用日志器的接口，如_debug()等
// 当然，用户也可包含自己的宏定义，如LOG_MY_DEBUG()等，方便使用

// 注意：对于自定义日志器，如果整个项目中使用，推荐使用全局日志器，避免重复创建日志器

namespace xzt
{
    namespace log
    {
        // 1. 提供日志器的全局获取接口，避免用户操作单例对象
        Logger::ptr getDefaultLogger()
        {
            return LoggerManager::getInstance().getDefaultLogger();
        }
        // 注意：在get获取默认日志器前需要创建创建该日志器，否则getLogger()返回为nullptr
        Logger::ptr getLogger(const std::string &loggerName)
        {
            return LoggerManager::getInstance().getLogger(loggerName);
        }
        
        /*
            利用构建者模式：LoggerBulider 与 LoggerManager 配合使用构建高度定制的日志器
            
            同时，注意创建时可以选择局部或全局的日志器，同样的bulid()方法，对于全局日志器会自动加入日志管理器中
        */
        Logger::ptr createBasicLogger(const std::string &loggerName)  // basic意味着只自定义日志器名，其他默认
        {
            LoggerBulider::ptr builder = std::shared_ptr<GlobalLoggerBulider>();
            builder->bulidLoggerName(loggerName);
            return builder->bulid();
        }
        // 参数说明：formatter参数具体特殊字符含义请参考format头文件中Formatter类, level参数同理
        // 默认创建出的日志器落地方向包括：控制台
        Logger::ptr createLogger(const std::string& loggerName,
                                    Level::value level,
                                    const std::string& formatter)
        {
            LoggerBulider::ptr builder = std::make_shared<GlobalLoggerBulider>();

            builder->bulidLoggerName(loggerName);
            builder->bulidLimitLevel(level);
            builder->bulidFormatter(formatter);
            // 对于落地方向的设定，可以有多个，不同落地方式buildSink()中的参数对应也不同
            builder->bulidSink<StdoutSink>();
            // builder->bulidSink<FileSink>("../../log.txt");
            // std::string rolling_file_basename = "../logs/data-";
            // builder->bulidSink<RollingBySizeFileSink>(rolling_file_basename, 1024 * 1024 * 5);  // 每5MB切分一次

            return builder->bulid();
        }

        // 2. 使用宏函数对日志器的接口进行代理（代理模式）-- 需要自己从(1)中获取日志器对象指针调用
        #define _debug(fmt, ...) _debug(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
        #define _info(fmt, ...) _info(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
        #define _warn(fmt, ...) _warn(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
        #define _error(fmt, ...) _error(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
        #define _fatal(fmt, ...) _fatal(__FILE__, __LINE__, fmt, ##__VA_ARGS__)

        // 3. 使用默认日志器情况下的简便调用方式
        // 利用条件编译，根据用户是否定义了 MY_NAMESPACE 来决定是否使用默认日志器
        //*************** MY_NAMESPACE *************/
        #define MY_NAMESPACE xzt::log
        //*************** MY_NAMESPACE *************/
        #ifdef MY_NAMESPACE
        #define DEFAULT_LOGGER MY_NAMESPACE::getDefaultLogger()
        #else
        #define DEFAULT_LOGGER getDefaultLogger()
        #endif

        // 这里注释是为了避免与用户自定义的宏冲突，若需要使用默认日志器请取消注释
        // #define LOG_DEBUG(fmt, ...) DEFAULT_LOGGER->_debug(fmt, ##__VA_ARGS__)
        // #define LOG_INFO(fmt, ...) DEFAULT_LOGGER->_info(fmt, ##__VA_ARGS__)
        // #define LOG_WARN(fmt, ...) DEFAULT_LOGGER->_warn(fmt, ##__VA_ARGS__)
        // #define LOG_ERROR(fmt, ...) DEFAULT_LOGGER->_error(fmt, ##__VA_ARGS__)
        // #define LOG_FATAL(fmt, ...) DEFAULT_LOGGER->_fatal(fmt, ##__VA_ARGS__)

        // 4. 其他需求定制
        // 日志器参数的定制 -- 基于使用者自己从(1)中获取日志器对象指针
        // 从易用性的角度考虑，牺牲了性能，但是对于使用者来说，可以更灵活简单地定制日志器的行为
        // 1) 设定日志器名称
        inline void ResetLoggerName(const Logger::ptr &logger, const std::string &new_name)
        {
            ResetLogger(logger).resetLoggerName(new_name);
        }
        // 2) 设定日志器限制输出等级
        inline void ResetLimitLevel(const Logger::ptr &logger, int new_level_num)  
        {
            ResetLogger(logger).resetLimitLevel(Level::fromNumber(new_level_num));
        }
        inline void ResetLimitLevel(const Logger::ptr &logger, Level::value new_level)  
        {
            ResetLogger(logger).resetLimitLevel(new_level);
        }
        // 3) 设定日志器输出格式, 具体特殊字符含义请参考format头文件中Formatter类
        inline void ResetFormatter(const Logger::ptr &logger, const std::string &new_pattern)
        {
            // 默认格式：[%d{%H:%M:%S}][%t][%p][%f:%l][%c]%T%m%n
            ResetLogger(logger).resetFormatter(std::make_shared<Formatter>(new_pattern));
        }
        inline void ResetFormatter(const Logger::ptr &logger, const Formatter::ptr &new_formatter)
        {
            // 默认格式：[%d{%H:%M:%S}][%t][%p][%f:%l][%c]%T%m%n
            ResetLogger(logger).resetFormatter(new_formatter);
        }
        // 4) 设定日志器落地方式，可以有多个落地方式，具体落地方式请参考sink头文件中LogSink类
        inline void ResetSinks(const Logger::ptr &logger, const std::vector<LogSink::ptr> &new_sinks)
        {
            // 注意不同LogSink对象的参数不同，请自行查看LogSink的子类构造函数参数
            ResetLogger(logger).resetSinks(new_sinks);
        }
    }
}

#endif // INTERFACE_HPP